package com.yuelao.netty.connect;

import com.yuelao.netty.msg.Request;
import com.yuelao.netty.util.MarshallingCodeCFactory;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.ReadTimeoutHandler;

import java.util.concurrent.TimeUnit;

/**
 * Description
 *
 * @author fengliye
 * @version v1.0
 * @date 14/12/2018 16:15
 * @modify detail
 * 版本       修改人        修改时间      修改内容描述
 * ---------------------------------------------
 * <p>
 * ---------------------------------------------
 */
public class ConnectClient {
    private EventLoopGroup group;
    private Bootstrap b;
    private ChannelFuture cf;

    // 单例
    private static class SingletonHolder {
        static final ConnectClient instance = new ConnectClient();
    }

    public static ConnectClient getInstance() {
        return SingletonHolder.instance;
    }

    private ConnectClient() {
        group = new NioEventLoopGroup();
        b = new Bootstrap();
        b.group(group)
                .channel(NioSocketChannel.class)
                .handler(new LoggingHandler(LogLevel.INFO))
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel sc) throws Exception {
                        sc.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingDecoder());
                        sc.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingEncoder());
                        //超时handler（当服务器端与客户端在指定时间以上没有任何进行通信，则会关闭通道）
                        sc.pipeline().addLast(new ReadTimeoutHandler(5));   // 时限5s, 读服务端超时没数据则断开
                        sc.pipeline().addLast(new ConnectClientHandler());
                    }
                });
    }

    public void connect() {
        try {
            this.cf = b.connect("127.0.0.1", 8765).sync();
            System.out.println("远程服务器已经连接, 可以进行数据交换");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public ChannelFuture getChannelFuture() {
        if (this.cf == null) {   //初次连接
            this.connect();
        }
        if (!this.cf.channel().isActive()) {  //重连
            this.connect();
        }
        return this.cf;
    }

    public static void main(String[] args) throws Exception {
        final ConnectClient c = ConnectClient.getInstance();

        ChannelFuture cf = c.getChannelFuture();
        for (int i = 1; i <= 3; i++) {
            Request request = new Request();
            request.setId("" + i);
            request.setName("request" + i);
            request.setRequestMessage("数据信息" + i);
            cf.channel().writeAndFlush(request);
            TimeUnit.SECONDS.sleep(4);  //间隔4s发送一次数据
        }

        cf.channel().closeFuture().sync(); //阻塞至超时关闭

        // 这里用子线程重连并发送数据一次
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println("进入子线程重连一次");
                    ChannelFuture cf = c.getChannelFuture();
                    assert true == cf.channel().isActive(); //断言
                    //再次发送数据
                    Request request = new Request();
                    request.setId("" + 4);
                    request.setName("request" + 4);
                    request.setRequestMessage("数据信息" + 4);
                    cf.channel().writeAndFlush(request);
                    cf.channel().closeFuture().sync();
                    System.out.println("子线程完成");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

        System.out.println("断开连接,主线程结束..");
    }
}
